package com.momoauth.api_client.controller;

import com.momoauth.api_client.entity.User;
import com.momoauth.api_client.entity.User_Role;
import com.momoauth.api_client.mapper.UserMapper;
import com.momoauth.api_client.mapper.UserRoleMapper;
import com.momoauth.api_client.utils.Utils;
import com.momoauth.common.core.result.ResponseResurt;
import com.momoauth.common.log.annotation.SystemLog;
import com.momoauth.api_client.utils.SecurityUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicInteger;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/login")
@Api(tags = "登录")
public class LoginController {

    @Resource
    UserMapper userMapper;

    @Resource
    UserRoleMapper userRoleMapper;

    @Resource
    RedisTemplate<String, Object> redisTemplate;

    @Resource
    RabbitTemplate rabbitTemplate;

    @Resource
    Utils utils;

    @Resource
    SecurityUtils securityUtils;

    @Resource
    private HttpServletRequest request;

    /**
     * 时间间隔（分钟）
     */
    private static final int TIME_INTERVAL = 1;
    /**
     * 登录失败重试次数上限
     */
    private static final int FAILED_RETRY_TIMES = 3;

    /**
     * redis记录用户登录失败次数key
     */
    private static final String USER_LOGIN_FAILED_COUNT = "USER:LOGIN:FAILED:COUNT:";

    /**
     * 登录请求
     * @param user
     * @param bindingResult
     * @return
     * @throws Exception
     */
    @ApiOperation(value = "登录请求")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "username", value = "用户名", required = true),
            @ApiImplicitParam(name = "password", value = "密码", required = true)
    })
    @RequestMapping(value = "/toLogin", method = RequestMethod.POST)
    @SystemLog(value = "登录请求", description = "ApiClient测试数据")
    public ResponseResurt toLogin(
            @Validated User user,
            BindingResult bindingResult
    ) throws Exception {
        // 非法参数验证
        if(bindingResult.hasErrors()){
            String errorMsg = bindingResult.getFieldError().getDefaultMessage();
            return ResponseResurt.error().msg(errorMsg);
        }
        // 判断是否存在有效用户
        Integer isExist = userMapper.existValidUser(user.getUsername());
        if (isExist == null) {
            return ResponseResurt.error().msg("该用户不存在或已被禁用。");
        }
        // 登录失败的情况下拒绝登录请求
        String key = USER_LOGIN_FAILED_COUNT + user.getUsername();
        RedisAtomicInteger counter = getRedisCounter(key);
        if (counter.get() >= FAILED_RETRY_TIMES) {
            return ResponseResurt.error().msg("登录失败次数已达上限，请稍后再试。");
        }
        // 请求登录（登录成功的情况下返回主键ID）
        Long userId = securityUtils.login(user.getUsername(), user.getPassword());
        if (userId != null && userId > 0) {
            String token = securityUtils.createToken(user.getUsername(), userId);
            // 登陆成功后删除Key
            redisTemplate.delete(key);
            // 创建登录日志
            this.createLoginLog(user.getUsername(), request);
            return ResponseResurt.success().msg("恭喜您，登录成功!").data(createData(token));
        } else {
            // 登录失败的情况下记录错误次数+1
            counter.getAndIncrement();
            return ResponseResurt.error().msg("很抱歉，密码错误。");
        }
    }

    //用户信息
    private Map createData(String token) throws Exception {
        Map<String,Object> map = new HashMap<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        long date = utils.getNowTime(sdf.format(new Date()), "90");
        Long userId = Long.parseLong(securityUtils.getClaimName(token, "userId"));
        List<User_Role> user_roleList = userRoleMapper.getUserRoleList(userId);
        map.put("username", securityUtils.getClaimName(token, "username"));
        map.put("user_roleList", user_roleList);
        map.put("token", token);
        map.put("iat", System.currentTimeMillis()); //签发时间 时间戳：毫秒
        map.put("exp", date); //过期时间 时间戳：毫秒
        return map;
    }

    //根据key获取计数器
    private RedisAtomicInteger getRedisCounter(String key) {
        RedisAtomicInteger counter = new RedisAtomicInteger(key, redisTemplate.getConnectionFactory());
        if (counter.get() == 0) {
            //设置过期时间，1分钟
            counter.expire(TIME_INTERVAL, TimeUnit.MINUTES);
        }
        return counter;
    }

    //创建登录日志
    private void createLoginLog(String username, HttpServletRequest request){
        Map<String,Object> map = new HashMap<>();
        map.put("username", username);
        map.put("loginIp", utils.getIpAddress(request));
        map.put("loginType", 1); //登录类型 1.电脑网页版
        rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
        rabbitTemplate.convertAndSend("createLoginLogExchange",
                "createLoginLogRouting", map);
    }
}
